package net.qiqbframework.commandhandling;


import net.qiqbframework.common.Registration;
import net.qiqbframework.messaging.annotation.*;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static net.qiqbframework.common.BuilderUtils.assertNonNull;


/**
 * 将任何 @CommandHandler 带注释的 Bean 转换为 MessageHandler 实现的适配器。
 * 每个带批注的方法都作为命令处理程序 CommandBus 订阅，该命令类型由该方法的参数指定
 */
public class AnnotationCommandHandlerAdapter<T> implements CommandMessageHandler {

    // annotatedEventListener
    private final T annotatedCommandHandler;

    private final AnnotatedHandlerInspector<T> handlerInspector;

    /**
     * 包装给定 annotatedCommandHandler的 ，允许它订阅到命令总线。
     *
     * @param annotatedCommandHandler 有 @CommandHandler 的对象
     */
    public AnnotationCommandHandlerAdapter(T annotatedCommandHandler) {
        this(annotatedCommandHandler, ClasspathParameterResolverFactory.forClass(annotatedCommandHandler.getClass()));
    }

    public AnnotationCommandHandlerAdapter(T annotatedCommandHandler,
                                           HandlerParameterResolverFactory parameterResolverFactory) {
        this(annotatedCommandHandler,
                parameterResolverFactory,
                ClasspathHandlerDefinition.forClass(annotatedCommandHandler.getClass()));
    }

    @SuppressWarnings("unchecked")
    public AnnotationCommandHandlerAdapter(T annotatedCommandHandler,
                                           HandlerParameterResolverFactory parameterResolverFactory,

                                           MessageHandlingMemberFactory handlerDefinition) {
        assertNonNull(annotatedCommandHandler, "The Annotated Command Handler may not be null");
        this.handlerInspector = AnnotatedHandlerInspector.inspectType((Class<T>) annotatedCommandHandler.getClass(),
                parameterResolverFactory,
                HandlerAttributesPostProcessor.EMPTY,
                handlerDefinition);

        this.annotatedCommandHandler = annotatedCommandHandler;
    }


    public Registration subscribe(CommandBus commandBus) {
        Collection<Registration> subscriptions =
                supportedCommandNames().stream()
                        .map(supportedCommand -> commandBus.subscribe(supportedCommand, this))
                        .collect(Collectors.toCollection(ArrayDeque::new));
        return () -> subscriptions.stream().map(Registration::cancel).reduce(Boolean::logicalOr).orElse(false);
    }


    @Override
    public Object handle(CommandMessage<?> command) throws Exception {
        MessageExecutableHandler handler =
                handlerInspector.getHandlers(annotatedCommandHandler.getClass())
                        .filter(ch -> ch.canHandle(command))
                        .findFirst()
                        .orElseThrow(() -> new CommandHandlerNotFoundException(command));

        return handlerInspector.chainedInterceptor(annotatedCommandHandler.getClass())
                .handle(command, annotatedCommandHandler, handler);
    }


    private Set<String> supportedCommandNames() {
        return handlerInspector.getAllHandlers()
                .values()
                .stream()
                .flatMap(Collection::stream)
                .map(ch -> ch.unwrap(CommandMessageExecutableHandler.class).orElse(null))
                .filter(Objects::nonNull)
                .map(CommandMessageExecutableHandler::commandNaming)
                .collect(Collectors.toSet());
    }
}
